﻿using System;
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.Xml;
using OpenCost.Common;
using OpenCost.Common.Interfaces.Input;
using OpenCost.Common.Readings;

namespace CurrentCost.InputPlugin.Envir
{
    public class Input : IInput
    {
        private SerialPort _serialPort;

        public SerialPort SerialPort
        {
            get { return _serialPort; }
        }


        public void createNewSerialPort(string portName)
        {
            _serialPort = new SerialPort(portName, 57600, Parity.None, 8, StopBits.One);
            _serialPort.DataReceived += SerialPortDataReceived;
        }

        private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string reading = ((SerialPort)sender).ReadLine();
            //after receiving the history batch for some reason the unit likes to send a '?' 
            //lets remove it
            if (reading[0] == '?')
            {
                reading.Remove(0, 1);
            }

            XmlDocument xmlDocument;
            try
            {
                xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(reading);
            }
            catch
            {
                return;
            }

            if (xmlDocument.GetElementsByTagName("hist").Count > 0)
            {
                //dealing with a history reading rather than realtime...
                //work out if its a hourly or daily reading
                var regex = new Regex("<h\\d\\d\\d>");
                if (regex.Match(xmlDocument.InnerXml).Success)
                {
                    //hourly
                    newHourlyHistory(xmlDocument);
                    newReading(xmlDocument,Enums.ReadingTypes.CurrentCostHourlyHistory);
                    return;
                }
                //daily
                newDailyHistory(xmlDocument);
                newReading(xmlDocument,Enums.ReadingTypes.CurrentCostDailyHistory);
                return;
            }
            //real time
            newRealTimeReading(xmlDocument);
            newReading(xmlDocument,Enums.ReadingTypes.CurrentCostRealTime);
        }

        private void newReading(XmlDocument xmlDocument,Enums.ReadingTypes readingType)
        {
            switch (readingType)
            {
                case Enums.ReadingTypes.CurrentCostRealTime:
                    NewReading(newRealTimeReading(xmlDocument));
                    break;
                case Enums.ReadingTypes.CurrentCostHourlyHistory:
                    NewReading(newHourlyHistory(xmlDocument));
                    break;
                case Enums.ReadingTypes.CurrentCostDailyHistory:
                    NewReading(newDailyHistory(xmlDocument));
                    break;
                default:
                    break;
            }
        }

        public string pluginName
        {
            get { return "Current Cost Reader"; }
        }

        public string pluginDescription
        {
            get { return "Current Cost Reader"; }
        }

        public object serialPort
        {
            get { return _serialPort; }
            set { _serialPort = (SerialPort)value; }
        }
        public event Delegates.NewReadingHandler NewReading;

        private Reading newDailyHistory(XmlDocument xmlDocument)
        {
            XmlNodeList dataList = xmlDocument.GetElementsByTagName("data");
            foreach (XmlElement nodeList in dataList)
            {
                if (nodeList.GetElementsByTagName("sensor").Item(0).InnerXml == "0")
                {
                    foreach (XmlElement element in nodeList)
                    {
                        var regex = new Regex("d\\d\\d\\d");
                        if (regex.Match(element.Name).Success)
                        {
                            //its a reading and not a sensor element
                            float reading = float.Parse(element.InnerText);
                            int daysAgo = int.Parse(element.Name.Remove(0, 1));
                            DateTime time =
                                DateTime.Now.Subtract(new TimeSpan(daysAgo, DateTime.Now.Hour, DateTime.Now.Minute,
                                                                   DateTime.Now.Second));
                        }
                    }
                }
            }
            return new DailyHistoryReading(){ReadingType = Enums.ReadingTypes.CurrentCostDailyHistory};
        }


        private Reading newHourlyHistory(XmlDocument xmlDocument)
        {
            XmlNodeList dataList = xmlDocument.GetElementsByTagName("data");
            foreach (XmlElement nodeList in dataList)
            {
                if (nodeList.GetElementsByTagName("sensor").Item(0).InnerXml == "0")
                {
                    foreach (XmlElement element in nodeList)
                    {
                        var regex = new Regex("h\\d\\d\\d");
                        if (regex.Match(element.Name).Success)
                        {
                            //its a reading and not a sensor element
                            float reading = float.Parse(element.InnerText);
                            int maxHoursAgo = int.Parse(element.Name.Remove(0, 1));
                            DateTime maxTime =
                                DateTime.Now.Subtract(new TimeSpan(maxHoursAgo, DateTime.Now.Minute, DateTime.Now.Second));
                            DateTime minTime = maxTime.Subtract(new TimeSpan(2, 0, 0));

                        }
                    }
                }
            }
            return new HourlyHistoryReading() {ReadingType = Enums.ReadingTypes.CurrentCostHourlyHistory};
        }

        private Reading newRealTimeReading(XmlDocument xmlDocument)
        {

            DateTime time =
                DateTime.Parse(DateTime.Today.ToShortDateString() + " " +
                               xmlDocument.GetElementsByTagName("time").Item(0).InnerText);
            float temp = float.Parse(xmlDocument.GetElementsByTagName("tmpr").Item(0).InnerText);
            string ch1Watts = "0", ch2Watts = "0", ch3Watts = "0";

            if (xmlDocument.SelectNodes("//ch1//watts").Count > 0)
            {
                ch1Watts = xmlDocument.SelectNodes("//ch1//watts").Item(0).InnerText;
            }
            if (xmlDocument.SelectNodes("//ch2//watts").Count > 0)
            {
                ch2Watts = xmlDocument.SelectNodes("//ch2//watts").Item(0).InnerText;
            }
            if (xmlDocument.SelectNodes("//ch3//watts").Count > 0)
            {
                ch3Watts = xmlDocument.SelectNodes("//ch3//watts").Item(0).InnerText;
            }
            string src = xmlDocument.GetElementsByTagName("src").Item(0).InnerText;
            int dsb = int.Parse(xmlDocument.GetElementsByTagName("dsb").Item(0).InnerText);
            int sensor = int.Parse(xmlDocument.GetElementsByTagName("sensor").Item(0).InnerText);
            int radioId = int.Parse(xmlDocument.GetElementsByTagName("id").Item(0).InnerText);


            RealTimeReading rtr = new RealTimeReading
            {
                ch1 = float.Parse(ch1Watts),
                ch2 = float.Parse(ch2Watts),
                ch3 = float.Parse(ch3Watts),
                radioid = radioId,
                sensor = sensor,
                src = src,
                temp = temp,
                time = time,
                dsb = dsb,
                ReadingType = Enums.ReadingTypes.CurrentCostRealTime
            };
            return rtr;
        }
    }
}
